/*
============================================================================
 Name        : sd_file.cpp
 Author      : Jian
 Version     :
 Copyright   : GPL
 Description : sd_file.cpp - source file
============================================================================
*/

/* INCLUDE FILES */
#include "sd_file.h"
#include "dd_log.h"

#include <f32file.h>
#include <UTF.H>
#include <BAUTILS.H>

#define __ToPtrC16(s)        TPtrC16((const TUint16*)s, User::StringLength((const TUint16*)s))
#define __ToPtrC8(s)         TPtrC8((const TUint8*)s, User::StringLength((const TUint8*)s))
#define __ToPtrC8Data(d,m)   TPtrC8((const TUint8*)d, m)

#define __ToPtr8(s,m)  TPtr8((TUint8*)s, m)
#define __ToPtr16(s,m)  TPtr16((TUint16*)s, m)

typedef struct {
    RFile* file ;
    int    error ;
} sd_symbian_file;

extern RFs* fileFs ;

HBufC16* SymUtf8ToUnicode(const TDesC8& aUtf8)
{
    HBufC16* buf16 = HBufC16::NewL(aUtf8.Length());
    TPtr16 ptr = buf16->Des();
    CnvUtfConverter::ConvertToUnicodeFromUtf8(ptr, aUtf8);
    return buf16;
}

static TBool _createFolder(const TDesC& aFolderName)
{
    TInt err = fileFs->MkDirAll(aFolderName) ;
    return err == KErrNone ;
}


static RFile* _openFile(const TDesC& name, DD_UINT flag)
{
    OpenAgain:

    TInt mode     = 0 ;
    TBool replace = EFalse ;

    if (flag == DD_FILE_REPLACE)
    {
        mode = EFileRead | EFileWrite ;
        replace = ETrue ;
    }
    else if (flag == DD_FILE_READ)
    {
        mode = EFileRead ;
    }
    else if (flag == DD_FILE_READ_WRITE)
    {
        mode = EFileRead | EFileWrite ;
    }
    else 
    {
        __DD_ASSERT_DEFENSE(0, return NULL) ;
    }

    mode |= EFileShareAny;

    RFile* file = NULL ;
    TRAPD(
        err,
        file = new(ELeave) RFile ;
    CleanupStack::PushL(file) ;
    User::LeaveIfError(replace ? file->Replace(*fileFs, name, mode) : file->Open(*fileFs, name, mode)) ;
    CleanupStack::Pop(file) ;
    ) ;

    if (err != KErrNone)
    {
        if (err == KErrPathNotFound)
        {
            TInt sep = name.LocateReverse('\\') ;

            if (!sep)
                goto OpenEnd ;

            if (!_createFolder(name.Left(sep + 1)))
                goto OpenEnd ;

            goto OpenAgain ;
        }
    }

    OpenEnd:

    return (err == KErrNone) ? file : NULL ;
}


sd_file* sd_file_open(const DD_UTF8* name, int flag) 
{
    __DD_ASSERT_DEFENSE(name, return NULL) ;

    HBufC* uName = SymUtf8ToUnicode(__ToPtrC8(name)) ;
    RFile* file = _openFile(*uName, flag) ;
    delete uName ;

    __DD_ASSERT_DEFENSE(file, return NULL) ;
    
    sd_symbian_file* ret = (sd_symbian_file*)dd_malloc(sizeof(sd_symbian_file)) ;
    ret->file = file ;
    ret->error = 0 ;

    return ret ;
}

void sd_file_close(sd_file* hFile) 
{
    __DD_ASSERT_DEFENSE(hFile, return) ;

    sd_symbian_file* file = (sd_symbian_file*)hFile ;
    file->file->Close() ;
    delete file->file ;
    dd_free(file) ;
}

int sd_file_read(sd_file* hFile, void* data, DD_UINT len) 
{
    __DD_ASSERT_DEFENSE(hFile && data && len > 0, return -1) ;

    sd_symbian_file* file = (sd_symbian_file*)hFile ;

    TPtr8 ptr = __ToPtr8(data, len) ;
    
    file->error = file->file->Read(ptr) ;
    
    __DD_ASSERT_DEFENSE(file->error == KErrNone, return -1) ;

    return ptr.Length();
}

int sd_file_write(sd_file* hFile, const void* data, DD_UINT len) 
{
    __DD_ASSERT_DEFENSE(hFile && data && len > 0, return -1) ;

    sd_symbian_file* file = (sd_symbian_file*)hFile ;
    file->error = file->file->Write(__ToPtrC8Data(data, len));
    
    __DD_ASSERT_DEFENSE(file->error == KErrNone, return -1) ;

    return len ;
}

int sd_file_tell(sd_file* hFile) 
{
    __DD_ASSERT_DEFENSE(hFile, return -1) ;
    
    sd_symbian_file* file = (sd_symbian_file*)hFile ;
    int pos = 0 ;

    file->error = file->file->Seek(ESeekCurrent, pos) ;

    __DD_ASSERT_DEFENSE(file->error == KErrNone, return -1) ;
    
    return pos ;
}


int sd_file_seek(sd_file* hFile, int offset, int whence) 
{
    __DD_ASSERT_DEFENSE(hFile, return -1) ;

    sd_symbian_file* file = (sd_symbian_file*)hFile ;
    file->error = 0 ;

    TSeek mode = (TSeek)(whence + 1) ;

    TInt pos     = offset ;
    file->error = file->file->Seek(mode, pos) ;

    __DD_ASSERT_DEFENSE(file->error == KErrNone, return -1) ;

    return pos ;
}

int sd_file_fulsh(sd_file* hFile) 
{
    __DD_ASSERT_DEFENSE(hFile, return -1) ;

    sd_symbian_file* file = (sd_symbian_file*)hFile ;
    file->error = 0 ;
    file->file->Flush() ;
    return 0 ;
}

int sd_file_eof(sd_file* hFile) 
{
    __DD_ASSERT_DEFENSE(hFile, return 1) ;
    sd_symbian_file* file = (sd_symbian_file*)hFile ;
    
    int size ;
    file->error = file->file->Size(size) ;
    
    __DD_ASSERT_DEFENSE(file->error == KErrNone, return 0) ;

    return sd_file_tell(file) == size ;
}

int sd_file_error(sd_file* hFile) 
{
    __DD_ASSERT_DEFENSE(hFile, return -1) ;
    sd_symbian_file* file = (sd_symbian_file*)hFile ;
    return file->error; 
}

int  sd_is_file_exist(const DD_UTF8* fileName) 
{
    __DD_ASSERT_DEFENSE(fileName, return 0) ;

    TPtrC8 ptr(__ToPtrC8(fileName)) ;
    if (ptr.Length() > 0 && (ptr[ptr.Length() - 1] == '\\'))
        return 0 ;

    int exist = 0 ;

    HBufC* uName = SymUtf8ToUnicode(ptr) ;
    if (BaflUtils::FileExists(*fileFs, *uName)) exist = 1 ;
    delete uName ;

    return exist ;
}

int  sd_get_file_size(const DD_UTF8* fileName, DD_UINT* size) 
{
    __DD_ASSERT_DEFENSE(fileName, return 0) ;

    HBufC* uName = SymUtf8ToUnicode(__ToPtrC8(fileName)) ;

    TInt fileSize = 0 ;
    TEntry entry;
    if (fileFs->Entry(*uName, entry) == KErrNone)
        fileSize = entry.iSize ;
    delete uName ;

    if (size) *size = fileSize ;
    return fileSize;
}

int  sd_truncate_file(const DD_UTF8* fileName, DD_UINT size) 
{
    __DD_ASSERT_DEFENSE(fileName, return -1) ;

    RFile file ;
    file.Open(*fileFs, *SymUtf8ToUnicode(__ToPtrC8(fileName)), EFileRead | EFileWrite | EFileShareAny) ;

    TInt errCode = file.SetSize(size) ;
    __DD_ASSERT_DEFENSE(errCode == KErrNone, return -1) ;
    return 0 ;
}

int  sd_is_folder_exist(const DD_UTF8* folderName) 
{
    __DD_ASSERT_DEFENSE(folderName, return 0) ;

    int exist = 0 ;

    HBufC* uName = SymUtf8ToUnicode(__ToPtrC8(folderName)) ;
    if (BaflUtils::FolderExists(*fileFs, *uName)) exist = 1 ;
    delete uName ;

    return exist ;
}

int  sd_create_folder(const DD_UTF8* folderName) 
{   
    __DD_ASSERT_DEFENSE(folderName, return -1) ;

    HBufC* uName = SymUtf8ToUnicode(__ToPtrC8(folderName)) ;
    int ret = _createFolder(*uName) ? 0 : -1 ;
    delete uName ;
    return ret ;
}


/* End of File */
